package com.example.czy.handler;

import com.example.czy.exception.BaseException;
import com.example.czy.utils.R;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Iterator;

/**
 * 全局自定义异常拦截器
 *
 * @author czy
 * @date 2022-04-18 12:45
 **/

@RestControllerAdvice
@NoArgsConstructor
@Slf4j
public class GlobalExceptionHandler {
    public static final String SERVER_ERROR_MSG = "系统异常，请联系管理员！";
    public static final String TYPE_ERROR_MSG = "类型错误！";
    public static final String PARAM_ERROR_MSG = "参数错误！";
    public static final String NOT_FOUND_MSG = "资源不存在！";
    public static final String CANNOT_BE_EMPTY_MSG = "不能为空！";

    @ExceptionHandler(BaseException.class)
    public R baseException(BaseException e) {
        log.error(getStackTrace(e));
        return R.failed(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    public R runtimeException(RuntimeException e) {
        log.error(getStackTrace(e));
        return R.failed(e.getMessage());
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public R illegalArgumentException(IllegalArgumentException e) {
        log.error(getStackTrace(e));
        return R.failed(HttpStatus.BAD_REQUEST.value(),  e.getMessage());
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public R methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.error(getStackTrace(e));
        return R.failed(HttpStatus.BAD_REQUEST.value(), e.getName() + TYPE_ERROR_MSG);
    }

    @ExceptionHandler(RestClientException.class)
    public R restClientException(RestClientException e) {
        log.error(getStackTrace(e));
        return R.failed(SERVER_ERROR_MSG);
    }

    @ExceptionHandler(FileNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public R fileNotFoundException(FileNotFoundException e) {
        log.error(getStackTrace(e));
        return R.failed(HttpStatus.NOT_FOUND.value(), NOT_FOUND_MSG);
    }

    private StringBuilder getStringBuilder(BindingResult bindingResult) {
        StringBuilder errorMessage = new StringBuilder();
        Iterator var3 = bindingResult.getFieldErrors().iterator();

        while (var3.hasNext()) {
            FieldError fieldError = (FieldError) var3.next();
            errorMessage.append(fieldError.getDefaultMessage()).append("\n");
        }

        log.error(errorMessage.toString());
        return errorMessage;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public R missingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error(getStackTrace(e));
        return R.failed(HttpStatus.BAD_REQUEST.value(), e.getParameterName() + CANNOT_BE_EMPTY_MSG);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error(getStackTrace(ex));
        StringBuilder errorMessage = this.getStringBuilder(ex.getBindingResult());
        return R.failed(HttpStatus.BAD_REQUEST.value(), errorMessage.toString());
    }

    @ExceptionHandler(BindException.class)
    public R bindException(BindException ex) {
        log.error(getStackTrace(ex));
        StringBuilder errorMessage = this.getStringBuilder(ex.getBindingResult());
        return R.failed(HttpStatus.BAD_REQUEST.value(), errorMessage.toString());
    }


    public static String getStackTrace(final Throwable throwable) {
        final StringWriter sw = new StringWriter();
        final PrintWriter pw = new PrintWriter(sw, true);
        throwable.printStackTrace(pw);
        return sw.getBuffer().toString();
    }

}

